home *** CD-ROM | disk | FTP | other *** search
/ SGI Developer Toolbox 6.1 / SGI Developer Toolbox 6.1 - Disc 4.iso / src / demos / GL / flight / comm.c < prev    next >
Text File  |  1994-08-01  |  16KB  |  782 lines

  1. /*
  2.  * Copyright 1984-1991, 1992, 1993, 1994, Silicon Graphics, Inc.
  3.  * All Rights Reserved.
  4.  *
  5.  * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Silicon Graphics, Inc.;
  6.  * the contents of this file may not be disclosed to third parties, copied or
  7.  * duplicated in any form, in whole or in part, without the prior written
  8.  * permission of Silicon Graphics, Inc.
  9.  *
  10.  * RESTRICTED RIGHTS LEGEND:
  11.  * Use, duplication or disclosure by the Government is subject to restrictions
  12.  * as set forth in subdivision (c)(1)(ii) of the Rights in Technical Data
  13.  * and Computer Software clause at DFARS 252.227-7013, and/or in similar or
  14.  * successor clauses in the FAR, DOD or NASA FAR Supplement. Unpublished -
  15.  * rights reserved under the Copyright Laws of the United States.
  16.  */
  17.  
  18. /*
  19.  *  flight/comm.c $Revision: 1.13 $
  20.  */
  21.  
  22. #include "flight.h"
  23. #include <stdio.h>
  24. #include "udpbrdcst.h"
  25.  
  26.  
  27. #define PID_ID(p) ((p)->planeid)
  28. #define REC_SIZE(p) sizeof(*p)
  29.  
  30. int enet;
  31. struct sockaddr_in dogaddr;
  32. struct sockaddr_in hostaddr;
  33.  
  34. int number_messages, MSG_SIZE;
  35. static char myname[NAME_LENGTH+1];
  36. static struct plane pbuf,    /* an extra plane structure    */
  37.             mbuf,    /* used only to outout messages    */
  38.             *pin;    /* pointer to input buffer    */
  39. Plane planes[MAX_PLANES];
  40. Plane plane_futures[MAX_PLANES];
  41. Plane messages[2*MAX_PLANES];
  42. Plane_hist plane_hists[MAX_PLANES];
  43.  
  44. /*
  45.  *  airshow input/output file control
  46.  */
  47. char *infile, *outfile;
  48. FILE *inf, *outf;
  49. static int numrecs;        /* number of plane records in inf */
  50. int read_pause = FALSE;
  51. int read_reset = FALSE;
  52. int read_backwards = FALSE;
  53. float read_speed = 1.0;
  54.  
  55.  
  56.  
  57.  
  58. /****************************************************************/
  59. /*        communication routines                */
  60. /****************************************************************/
  61.  
  62. /* init ethernet interface, discard my packets, no debug    */
  63. InitComm(game)
  64.     char *game;
  65. {
  66.     char buf[80];
  67.     register char *name;
  68.     register int i;
  69.     register Plane pp;
  70.     register Plane_hist pph;
  71.     extern char *getenv();
  72.  
  73.     pin = &pbuf;
  74.     MSG_SIZE = ((int)&mbuf.mtype)-(int)&mbuf.azimuth;
  75.     number_messages = 0;
  76.     for (i = 0; i < MAX_PLANES; i++)
  77.     {
  78.     pp = (Plane)malloc(sizeof(struct plane));
  79.     pp->alive = -1;
  80.     planes[i] = pp;
  81.     pp = (Plane)malloc(sizeof(struct plane));
  82.     pp->alive = -1;
  83.     messages[i] = pp;
  84.     pp = (Plane)malloc(sizeof(struct plane));
  85.     pp->alive = -1;
  86.     messages[i+MAX_PLANES] = pp;
  87.     pph = (Plane_hist)malloc(sizeof(struct plane_hist));
  88.     pph->malive = 0;
  89.     plane_hists[i] = pph;
  90.     if (infile)
  91.     {
  92.         pp = (Plane)malloc(sizeof(struct plane));
  93.         pp->alive = -1;
  94.         plane_futures[i] = pp;
  95.     }
  96.     }
  97.     pp = planes[0];
  98.     if (infile || outfile)
  99.     {
  100.     numrecs = 0;
  101.     if (infile)
  102.     {
  103.         inf = fopen(infile, "r");
  104.         if (inf == NULL)
  105.         {
  106.         fprintf(stderr, "input file '%s' not found\n", infile);
  107.         exit(3);
  108.         }
  109.         fread(&numrecs, sizeof(numrecs), 1, inf);
  110.     }
  111.     if (outfile)
  112.     {
  113.         outf = fopen(outfile, "w");
  114.         if (outf == NULL)
  115.         {
  116.         fprintf(stderr, "could not open output file '%s'\n", outfile);
  117.         exit(3);
  118.         }
  119.         numrecs++;
  120.         fwrite(&numrecs, sizeof(numrecs), 1, outf);
  121.         numrecs--;
  122.     }
  123.     PLANE_ID(pp) = getpid();
  124.     PID_ID(pp) = PLANE_ID(pp);
  125.     enet = -1;
  126.     }
  127.     else
  128.     {
  129.     enet = getbroadcast("sgi-dogfight", &dogaddr);
  130.     gethostaddr(&hostaddr);
  131.     PLANE_ID(pp) = hostaddr.sin_addr.s_addr;
  132.     PID_ID(pp) = PLANE_ID(pp);
  133.     if (enet < 0)
  134.     {
  135.         /*
  136.          *  exit graphics
  137.          */
  138.         restore_map();
  139.         drawmode(PUPDRAW);
  140.         color(0);
  141.         clear();
  142.         drawmode(UNDERDRAW);
  143.         color(0);
  144.         clear();
  145.         gexit();
  146.  
  147.         if (enet == -2)
  148.         udp_warning();
  149.         else
  150.         fprintf(stderr, "Ethernet init failed\n");
  151.  
  152.         exit(enet);
  153.     }
  154.     }
  155.  
  156.     pp->myname[0] = '\0';
  157.     name = getenv("DOGID");
  158.     if (name && *name)
  159.     strncpy(pp->myname, name, NAME_LENGTH);
  160.     else if (game)
  161.     while (!pp->myname[0])
  162.         get_text("Enter your name: ", &pp->myname[0], NAME_LENGTH);
  163.     pp->version = 5;
  164.     pp->cmd = DATA_PACKET;
  165.     pp->won = 0;
  166.     pp->lost = 0;
  167.  
  168.     mbuf = *pp;            /* init msg packet    */
  169.     mbuf.cmd = MSG_PACKET;
  170.     mbuf.status = MSTART;
  171.     if (game)
  172.     {
  173.     sprintf(buf, "joining the dogfight as a %s", game);
  174.     broadcast(buf);
  175.     }
  176. }
  177.  
  178. ExitComm()
  179. {
  180.     broadcast("signing off");
  181.  
  182.     if (inf != NULL)
  183.     fclose(inf);
  184.     if (outf != NULL)
  185.     fclose(outf);
  186. }
  187.  
  188. /* return a pointer to a new message pointer    */
  189. Plane *new_msg()
  190. {
  191.     register Plane *m;
  192.  
  193.     m = &messages[number_messages];    /* return pointer to last msg    */
  194.     number_messages++;            /* bump count        */
  195.     ringbell();                /* and ring bell    */
  196.     return(m);
  197. }
  198.  
  199. /* find the plane whose enet id matches pfind, return it if found */
  200. Plane lookup_plane(id)
  201.     register long id;
  202. {
  203.     register Plane p, *pp;
  204.  
  205.     FOR_EACH_PLANE (p, pp)
  206.     {
  207.     if (id == PLANE_ID(p))
  208.         return(p);
  209.     }
  210.     return(NULL);
  211. }
  212.  
  213. /* find the plane whose enet id matches pfind, create one if needed */
  214. Plane *find_plane(pfind)
  215.     Plane pfind;
  216. {
  217.     register long id;
  218.     register Plane p, *pp;
  219.  
  220.     id = PLANE_ID(pfind);
  221.     FOR_EACH_PLANE (p, pp)
  222.     {
  223.     if (id == PLANE_ID(p))
  224.         return(pp-1);
  225.     }
  226.  
  227.     /*
  228.      *  This is a new plane
  229.      */
  230.     addplane(pfind);        /* call user routine    */
  231.     bcopy(pfind, p, sizeof(*p));
  232.     return(pp-1);        /* return pointer    */
  233. }
  234.  
  235. /*
  236.  *  decrement each planes alive counter and check if its dead
  237.  */
  238. check_alive(dec)
  239.     register int dec;
  240. {
  241.     register int n;
  242.     register Plane p, *pp, *ppf, temp;
  243.     register Plane_hist ph, *pph, htemp;
  244.  
  245.     FOR_EACH_PLANE_AND_HIST (p, pp, ph, pph)    /* for each alive plane    */
  246.     {
  247.     p->alive -= dec;        /* decrement alive counter    */
  248.     if (p->alive <= 0)        /* if its dead            */
  249.     {
  250.         n = delplane(p);        /* call user routine        */
  251.  
  252.         /*
  253.          *  swap last with dead plane
  254.          */
  255.         temp = *--pp;
  256.         *pp++ = planes[n];
  257.         planes[n] = temp;
  258.         htemp = *--pph;
  259.         *pph++ = plane_hists[n];
  260.         plane_hists[n] = htemp;
  261.         if (inf)
  262.         {
  263.         ppf = pp - planes + plane_futures;
  264.         temp = *--ppf;
  265.         *ppf++ = plane_futures[n];
  266.         plane_futures[n] = temp;
  267.         }
  268.     }
  269.     }
  270.     FOR_EACH_MSG (p, pp)        /* for each alive message    */
  271.     {
  272.     p->alive -= dec;        /* decrement alive counter    */
  273.     if (p->alive <= 0)        /* if its dead            */
  274.     {
  275.         number_messages--;
  276.         temp = *--pp;        /* swap last with dead message    */
  277.         *pp++ = messages[number_messages];
  278.         messages[number_messages] = temp;
  279.     }
  280.     }
  281. }
  282.  
  283.  
  284. kill_obsolete()
  285. {
  286.     kill_me("You are running an obsolete version, try copying a new version");
  287. }
  288.  
  289.  
  290. kill_me(msg)
  291.     char *msg;
  292. {
  293.     gexit();
  294.     fprintf(stderr, msg);    fprintf(stderr, "\n");
  295.     exit(1);
  296. }
  297.  
  298.  
  299.  
  300. /*
  301.  *  get other planes data into global data structures
  302.  *  returns whether this plane got blown up or not
  303.  */
  304. Plane get_indata(count)
  305.     int count;
  306. {
  307.     register Plane p, *pp, retval;
  308.     Plane pf, *ppf, ptmp;
  309.     float current_time;
  310.     static float future_time = 0.0;
  311.     float last_m[MAX_PLANES][4];
  312.     int i;
  313.  
  314.     retval = NULL;
  315.  
  316.     if (read_pause)
  317.     return(retval);
  318.  
  319.     /*
  320.      *  throw out stale airplanes
  321.      */
  322.     check_alive(count);
  323.  
  324.     if (inf)
  325.     {
  326.     if (read_reset)
  327.         future_time = 0.0;
  328.  
  329.     current_time = (1.0 / tps) * read_speed;
  330.  
  331.     FOR_EACH_PLANE_I (i, p)
  332.         if (last_m[i][3] = p->mstatus)
  333.         {
  334.         last_m[i][0] = p->mx;
  335.         last_m[i][1] = p->my;
  336.         last_m[i][2] = p->mz;
  337.         }
  338.     }
  339.  
  340.     /*
  341.      *  read all packets that are there
  342.      */
  343.     while (1)
  344.     {
  345.     if (inf && future_time > 0.0)
  346.     {
  347.         if (current_time >= future_time)
  348.         {
  349.         current_time -= future_time;
  350.         future_time = 0.0;
  351.  
  352.         FOR_EACH_PLANE_AND_FUTURE (p, pp, pf, ppf)
  353.         {
  354.             ptmp = *--pp;
  355.             *pp++ = *--ppf;
  356.             *ppf++ = ptmp;
  357.         }
  358.         }
  359.         else
  360.         {
  361.         FOR_EACH_PLANE_AND_FUTURE (p, pp, pf, ppf)
  362.             partial_plane_move(p, pf, current_time / future_time);
  363.  
  364.         future_time -= current_time;
  365.         current_time = 0.0;
  366.         }
  367.  
  368.         if (current_time == 0.0)
  369.         {
  370.         FOR_EACH_PLANE_I (i, p)
  371.         {
  372.             if (last_m[i][3])
  373.             {
  374.             p->last_mx = last_m[i][0];
  375.             p->last_my = last_m[i][1];
  376.             p->last_mz = last_m[i][2];
  377.             }
  378.             if (outf)
  379.             fwrite(&PID_ID(p), REC_SIZE(p), 1, outf);
  380.         }
  381.         return(retval);
  382.         }
  383.     }
  384.  
  385.     while ((enet >= 0)? recvbroadcast(enet, pin, sizeof(*pin), IGNOREOWNMSG)
  386.                 :
  387.                 read_infile(pin, current_time))
  388.         switch (pin->cmd)
  389.         {
  390.         case DATA_PACKET:
  391.             convert_planetype(pin);
  392.  
  393.             /*
  394.              *  see if he killed me
  395.              */
  396.             if (pin->mstatus && pin->mkill == PLANE_ID(&mbuf))
  397.             retval = pin;        /* he killed me    */
  398.  
  399.             /*
  400.              *  find the plane
  401.              */
  402.             pp = find_plane(pin);
  403.  
  404.             /*
  405.              *  and swap the data
  406.              */
  407.             if (inf)
  408.             {
  409.             future_time = 1.0 / pin->tps;
  410.             pin->tps = tps;
  411.  
  412.             ppf = pp - planes + plane_futures;
  413.             p = *ppf;
  414.             *ppf = pin;
  415.             pin = p;
  416.             }
  417.             else
  418.             {
  419.             p = *pp;
  420.             *pp = pin;
  421.             pin = p;
  422.             }
  423.             break;
  424.         case MSG_PACKET:
  425.         case SUPERKILL_PACKET:
  426.             if (pin->version < mbuf.version)
  427.             {
  428.             mbuf.cmd = KILL_PACKET;    /* send out a kill cmd    */
  429.             send_outdata(&mbuf);
  430.             mbuf.cmd = MSG_PACKET;    /* restore it to msg    */
  431.             }
  432.             if (*(long *)&pin->won == NULL_PLANE_ID ||
  433.             *(long *)&pin->won == PLANE_ID(&mbuf))
  434.             {                /* if broadcast or sent to me */
  435.             if (pin->cmd == SUPERKILL_PACKET)
  436.                 kill_me("You were logged off by a wizard");
  437.             pp = new_msg();        /* grab a new message    */
  438.             p = *pp;        /* and swap data    */
  439.             *pp = pin;
  440.             pin = p;
  441.             }
  442.             break;
  443.         case KILL_PACKET:
  444.             if (pin->version > mbuf.version)
  445.             kill_obsolete();
  446.             break;
  447.         default:            /* unknown packet type    */
  448.             kill_obsolete();        /* say bye bye        */
  449.         }
  450.  
  451.     if (!inf)
  452.         return(retval);
  453.     }
  454. }
  455.  
  456. int read_infile(Plane p, float current_time)
  457. {
  458.     static int count;
  459.  
  460.     if (inf == NULL)
  461.     return(0);
  462.  
  463.     if (read_reset)
  464.     {
  465.     fseek(inf, 4, SEEK_SET);        /* reposition on byte 4    */
  466.     read_reset = FALSE;
  467.     }
  468.  
  469.     if (count == numrecs)
  470.     return(count = 0);
  471.  
  472.     if (read_backwards)
  473.     {
  474.     if (fseek(inf, -2 * sizeof(*p), SEEK_CUR) || ftell(inf) <= 0)
  475.         fseek(inf, -sizeof(*p), SEEK_END);
  476.     }
  477.  
  478.     if (fread(&PID_ID(p), REC_SIZE(p), 1, inf) == 0)
  479.     {
  480.     register Plane pmsg;
  481.  
  482.     fseek(inf, 4, SEEK_SET);        /* reposition on byte 4    */
  483.     pmsg = *new_msg();            /* grab a new msg    */
  484.     pmsg->alive = TPS * 4;
  485.     strncpy(pmsg->myname, "disk reader", NAME_LENGTH);
  486.     *(long *)&pmsg->won = NULL_PLANE_ID;
  487.     strncpy(&pmsg->azimuth, "end of file - starting over", MSG_SIZE);
  488.  
  489.     if (fread(&PID_ID(p), REC_SIZE(p), 1, inf) == 0)
  490.         fprintf(stderr, "comm: fread returned 0\n");
  491.     }
  492.  
  493.     PLANE_ID(p) = PID_ID(p);
  494.     if (p->cmd == DATA_PACKET)
  495.     count++;
  496.     if (outf && p->cmd != DATA_PACKET)
  497.     fwrite(&PID_ID(p), REC_SIZE(p), 1, outf);
  498.     return(1);
  499. }
  500.  
  501.  
  502. rewind_if(d)
  503. {
  504.     register Plane p;
  505.  
  506.     if (inf)
  507.     {
  508.     fseek(inf, REC_SIZE(p)*d, SEEK_CUR);
  509.     if (ftell(inf) <= 3)
  510.         fseek(inf, 4, SEEK_SET);        /* reposition on byte 4    */
  511.     }
  512. }
  513.  
  514. /* send out my plane's data    */
  515. send_outdata(p)
  516.     register Plane p;
  517. {
  518.     static unsigned short last_status;
  519.  
  520.     last_status = MSTART;
  521.  
  522.     p->tps = tps;
  523.  
  524.     if (enet >= 0)
  525.     {
  526.     if (last_status > 0)
  527.         sendbroadcast(enet, p, sizeof(*p), &dogaddr);
  528.     }
  529.     else if (outf)
  530.     fwrite(&PID_ID(p), REC_SIZE(p), 1, outf);
  531.  
  532.     last_status = p->status + p->mstatus;
  533. }
  534.  
  535. broadcast(msg)
  536.     char *msg;
  537. {
  538.     register Plane p;
  539.  
  540.     if (dogfight)
  541.     {
  542.     send_message(msg, NULL_PLANE_ID);
  543.     p = *new_msg();            /* grab a new msg    */
  544.     *p = mbuf;            /* copy data to it    */
  545.     }
  546. }
  547.  
  548. send_message(msg, to)
  549.     char *msg;
  550.     long to;
  551. {
  552.     register Plane psend;
  553.  
  554.     psend = &mbuf;
  555.     psend->alive = TPS * 4;
  556.     *(long *)&psend->won = to;
  557.     strncpy(&psend->azimuth, msg, MSG_SIZE);
  558.  
  559.     if (!strcmp(msg, "SUPERKILL"))
  560.     {
  561.     psend->cmd = SUPERKILL_PACKET;
  562.     send_outdata(psend);
  563.     psend->cmd = MSG_PACKET;
  564.     }
  565.     else
  566.     send_outdata(psend);
  567. }
  568.  
  569.  
  570. #define llx 200
  571. #define urx (llx+600)
  572. #define lly 500
  573. #define ury (lly+40)
  574.  
  575. get_text(prompt, user_buf, maxlen)
  576.     char *prompt, *user_buf;
  577.     int maxlen;
  578. {
  579.     short type, val;
  580.     char strbuf[132];
  581.     register char c, *str, *end;
  582.  
  583.     viewport(llx, urx, lly, ury);
  584.     ortho2(llx-.5, urx+.5, lly-.5, ury+.5);
  585.     end = strbuf + maxlen +1;
  586.     cursoff();
  587.  
  588. ctrlu:
  589.     str = strbuf;
  590.     *str++ = '_';
  591.     *str = '\0';
  592.  
  593.     while (1)
  594.     {
  595.     COLOR(C_BLACK);
  596.     clear();
  597.     COLOR(C_WHITE);
  598.     recti(llx, lly, urx, ury);
  599.     cmov2i(llx+12, lly+10);
  600.     charstr(prompt);
  601.     charstr(strbuf);
  602.     swapbuffers();
  603.  
  604.     type = qread(&val);
  605.     if (type == KEYBD)
  606.     {
  607.         c = val;
  608.         if (c == '\r')
  609.         goto all_done;
  610.         else if (c == '')
  611.         goto ctrlu;
  612.         else if (c == '' || c == '')
  613.         {
  614.         if (str-1 != strbuf)    /* if not at start    */
  615.         {
  616.             str -= 2;        /* then backup 2 chars    */
  617.             *str++ = '_';    /* reinsert cursor, null*/
  618.             *str = '\0';
  619.         }
  620.         }
  621.         else if (c >= ' ')        /* if its a valid char    */
  622.         {
  623.         if (str < end)        /* check to see if there's room    */
  624.         {
  625.             *--str = c;
  626.             *++str = '_';    /* reinsert cursor, null*/
  627.             *++str = '\0';
  628.         }
  629.         else ;
  630.         }
  631.     }
  632.     else;                /* not a keyboard */
  633.     }
  634.  
  635. all_done:
  636.     *--str = '\0';            /* remove cursor    */
  637.     strcpy(user_buf, strbuf);
  638.     curson();
  639.     COLOR(C_BLACK);
  640.     clear();
  641.     swapbuffers();
  642.     clear();
  643. }
  644.  
  645.  
  646.  
  647. draw_messages()
  648. {
  649.     register Plane p, *pp;
  650.     register int y, dy;
  651.  
  652.     COLOR(C_ORANGE);
  653.     if (hud)
  654.     {
  655.     y = ymaxscreen - 44;
  656.     dy = 24;
  657.     }
  658.     else if (shadow)
  659.     {
  660.     y = 180;
  661.     dy = 10;
  662.     }
  663.     else
  664.     {
  665.     y = 80;
  666.     dy = 10;
  667.     }
  668.  
  669.     FOR_EACH_MSG (p, pp)
  670.     {
  671.     if (hud)
  672.         cmov2i(50, y);
  673.     else
  674.         cmov2i(-195, y);
  675.     if (*(long *)&p->won == NULL_PLANE_ID)
  676.         charstr("Broadcast message from ");
  677.     else
  678.         charstr("Message from ");
  679.     charstr(p->myname);
  680.     charstr(": ");
  681.     charstr((char *)(&p->azimuth));
  682.     y -= dy;
  683.     }
  684. }
  685.  
  686.  
  687. udp_warning()
  688. {
  689.     printf("\n");
  690.     printf("To run dog over the network you must have the following line\n");
  691.     printf("in your /etc/services file.\n");
  692.     printf("\n");
  693.     printf("sgi-dogfight    5130/udp        # dogfight demo\n");
  694.     printf("\n");
  695.     printf("WARNING some machines can not handle large numbers of udp\n");
  696.     printf("broadcast packets.  If you have machines from other vendors\n");
  697.     printf("on your network, running dog on your network may bring them\n");
  698.     printf("to a halt.  VAXes are known to have this problem.\n");
  699. }
  700.  
  701.  
  702. /*
  703.  *  old plane types
  704.  *  currently used on 3XXX and non GT 4Ds
  705.  */
  706. #define OLD_C150 1000
  707. #define OLD_B747 1010
  708. #define OLD_F15  1020
  709. #define OLD_F16  1030
  710. #define OLD_F18  1040
  711. #define OLD_P38  1050
  712. #define OLD_F16W 1060
  713. #define OLD_P38W 1070
  714.  
  715.  
  716. /*
  717.  *  convert plane types from old form to new
  718.  */
  719. convert_planetype(p)
  720.     struct plane *p;
  721. {
  722.     if (p->type >= OLD_C150 && p->type <= OLD_P38W)
  723.     switch(p->type)
  724.     {
  725.         case OLD_C150:
  726.         p->type = C150;
  727.         break;
  728.         case OLD_B747:
  729.         p->type = B747;
  730.         break;
  731.         case OLD_F15:
  732.         p->type = F15;
  733.         break;
  734.         case OLD_F16:
  735.         case OLD_F16W:
  736.         p->type = F16;
  737.         break;
  738.         case OLD_F18:
  739.         p->type = F18;
  740.         break;
  741.         case OLD_P38:
  742.         case OLD_P38W:
  743.         p->type = P38;
  744.         break;
  745.         default:
  746.         printf("Unknown plane type\n");
  747.     }
  748. }
  749.  
  750.  
  751. #define NORMALIZE(A, B);    \
  752. {                \
  753.     i = B - A;            \
  754.     if (i >= 1800)        \
  755.     A += 3600;        \
  756.     else if (i <= -1800)    \
  757.     B += 3600;        \
  758. }
  759.  
  760. void partial_plane_move(Plane p0, Plane p1, float percent)
  761. {
  762.     int i;
  763.  
  764.     p0->x += (p1->x - p0->x) * percent;
  765.     p0->y += (p1->y - p0->y) * percent;
  766.     p0->z += (p1->z - p0->z) * percent;
  767.  
  768.     NORMALIZE(p0->azimuth, p1->azimuth);
  769.     p0->azimuth += (p1->azimuth - p0->azimuth) * percent;
  770.     NORMALIZE(p0->elevation, p1->elevation);
  771.     p0->elevation += (p1->elevation - p0->elevation) * percent;
  772.     NORMALIZE(p0->twist, p1->twist);
  773.     p0->twist += (p1->twist - p0->twist) * percent;
  774.  
  775.     if (p0->mstatus)
  776.     {
  777.     p0->mx += (p1->mx - p0->mx) * percent;
  778.     p0->my += (p1->my - p0->my) * percent;
  779.     p0->mz += (p1->mz - p0->mz) * percent;
  780.     }
  781. }
  782.